#|_______________________
 |
 | *MAIN-WINDOWFRAME*  *MAIN-LISTENER*
 |
 |   Creates two window-managers which manage sizing and location and the showing and
 | hiding of the mainframe and its listener. The managers are created with the statement
 |         (main-window)
 | which creates the managers and binds the variables
 |         *main-windowframe* and *main-listener* 
 | to the manager object instances. The function returns the main-windowframe-manager 
 | object instance. The instance has a :main-listener slot which contains the 
 | main-listener-manager object id.
 |
 |     To control the size and location of the mainframe and its listener, you can send 
 | the managers the :size and :location messages. For example:
 |         (send *main-windowframe* :size)  or 
 |         (send *main-listener* :location)
 |
 |     Once the mainframe is showing you can hide it with the :hide-window message 
 | and re-show it with the :show-window message. NOTE: It is not possible to show the
 | mainframe with the :show-window message if it is minimized. In fact, these messages
 | do not minimize and restore the window, rather, they hide by locating the window
 | off-screen and show by relocating the window to its former position. There is no
 | way to send a message to minimize or restore the window.
 |
 |     You can also send the :show-window and :hide-window messages to the listener 
 | to hide and show the listener within the mainframe. Of course, you can only see 
 | the result when the mainframe is showing.  
 |
 |     You can maximize the mainframe or listener by sending it the :maximize message. 
 | You can restore the window to its former size with the :restore message. Once again,
 | these do not use the ms-windows features to do this, and do not interact properly
 | with these features.
 |_______________________
 |#


(defun main-window (&key (size '(600 400)) (location '(30 30)))
  (setf *main-windowframe* (main-frame :size size :location location))
  (setf *main-listener* (main-listener :size nil :location nil))
  (send *main-windowframe* :main-listener *main-listener*)
  *main-windowframe*)

(defun main-frame (&key (size '(600 400)) (location '(30 30)))
  (send main-windowframe-proto :new size location))

(defproto main-windowframe-proto '(real-loc-size main-listener) () window-proto)

(defmeth main-windowframe-proto :isnew (&optional (size '(600 400)) (location '(30 30)))
  (send self :real-loc-size (combine location size))
  (apply #'mainwindow (combine location size))
  self)

(defmeth main-windowframe-proto :real-loc-size (&optional (list nil set))
"Message args: (&optional list)
 Sets or retrieves the real-location and size of the main window. Does not change the location or size."
  (if set (setf (slot-value 'real-loc-size) list))
  (slot-value 'real-loc-size))

(defmeth main-windowframe-proto :main-listener (&optional (objid nil set))
"Message args: (&optional objid)
 Sets or retrieves the object identification of the main listener"
  (if set (setf (slot-value 'main-listener) objid))
  (slot-value 'main-listener))


(defmeth main-windowframe-proto :size (&optional h w)
  (cond
    ((and h (not w)) (error "width must be specified when height is specified"))
    ((and h w) (apply #'mainwindow (combine (select (mainwindow) '(0 1)) h w))))
  (send self :real-loc-size (mainwindow))
  (select (mainwindow) '(2 3)))

(defmeth main-windowframe-proto :location (&optional x y)
  (cond
    ((and x (not y)) (error "y-location must be specified when x-location is specified"))
    ((and x y) (apply #'mainwindow (combine x y (select (mainwindow) '(2 3))))))
  (send self :real-loc-size (mainwindow))
  (select (mainwindow) '(0 1)))
  
(defmeth main-windowframe-proto :hide-window ()
  (send self :real-loc-size (mainwindow))
  (mainwindow 2000 2000 1 1))

(defmeth main-windowframe-proto :show-window ()
  (apply #'mainwindow (send self :real-loc-size)))

(defmeth main-windowframe-proto :maximize ()
  (apply #'mainwindow (combine 4 24 *effective-screen-size*)))

(defmeth main-windowframe-proto :restore ()
  (apply #'mainwindow (send self :real-loc-size)))


#|_______________________
 |
 | *MAIN-LISTENER*
 |_______________________
 |#


(defun main-listener (&key (size nil) (location nil) (frame nil))
  (send main-listener-proto :new size location frame))

(defproto main-listener-proto '(real-loc-size main-window-frame) () window-proto)

(defmeth main-listener-proto :isnew (&optional (size nil) (location nil) (frame nil))
"Args: (&optional (size nil) (location nil))
Generates a new listener-manager-object and posistions the listener window inside the mainframe. Listener is located at LOCATION and is of size SIZE when both are specified. If both are not specified, listener is maximized inside mainframe. If size is specified but location is not, a window of size SIZE is generated and located at the upper-left corner of the mainframe. If location is specified and size is not, a window is generated at the specified location with a size which fits the listener inside the mainframe. Returns the listener-manager object."
  (send self :main-window-frame frame)
  (cond 
    ((and (not size) (not location)) 
     (send self :real-loc-size (send self :maximize)))
    ((and (not size) location) 
     (send self :real-loc-size (send self :fit-listener-in-frame location)))
    ((and size (not location)) 
     (send self :real-loc-size (setf 0 0 size))
     (apply #'listener (send self :real-loc-size)))
    (t 
     (send self :real-loc-size (combine location size))
     (apply #'listener (send self :real-loc-size))))
  self)

(defmeth main-listener-proto :real-loc-size (&optional (list nil set))
"Message args: (&optional list)
 Sets or retrieves the real-location and size of the main window. Does not change the location or size."
  (if set (setf (slot-value 'real-loc-size) list))
  (slot-value 'real-loc-size))

(defmeth main-listener-proto :main-window-frame (&optional (objid nil set))
"Message args: (&optional objid)
 Sets or retrieves the object identification of the main window frame"
  (if set (setf (slot-value 'main-window-frame) objid))
  (slot-value 'main-window-frame))

(defmeth main-listener-proto :maximize ()
  (apply #'listener (combine 0 0 (- (select (mainwindow) '(2 3)) '( 0 18)))))

(defmeth main-listener-proto :restore ()
  (apply #'listener (send self :real-loc-size)))

(defmeth main-listener-proto :size (&optional h w)
  (cond
    ((and h (not w)) (error "width must be specified when height is specified"))
    ((and h w) (apply #'listener (combine (select (listener) '(0 1)) h w))))
  (send self :real-loc-size (listener))
  (select (listener) '(2 3)))

(defmeth main-listener-proto :location (&optional x y)
  (cond
    ((and x (not y)) (error "y-location must be specified when x-location is specified"))
    ((and x y) (apply #'listener (combine x y (select (listener) '(2 3))))))
  (send self :real-loc-size (listener))
  (select (listener) '(0 1)))

(defmeth main-listener-proto :fit-in-frame (&optional x y)
  (cond
    ((and x (not y)) (error "y-location must be specified when x-location is specified"))
    ((and (not x) (not y)) 
     (setf x (first (listener)))
     (setf y (second (listener)))
     (apply #'listener (combine x y (- (select (mainwindow) '(2 3)) (list x (+ y 18))))))
    ((and x y)
     (apply #'listener (combine x y (select (- (mainwindow) (list 0 0 x y)) '(2 3))))))
  (send self :real-loc-size (listener))
  (listener))

(defmeth main-listener-proto :hide-window ()
  (send self :real-loc-size (listener))
  (listener 2000 2000 1 1))

(defmeth main-listener-proto :show-window ()
  (apply #'listener (send self :real=loc-size)))


